package scatter.recommend.rest.recommend.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import scatter.common.rest.monitor.MonitorTool;
import scatter.recommend.rest.recommend.IRecommender;
import scatter.recommend.rest.recommend.IRecommenderChain;
import scatter.recommend.rest.recommend.dto.RecommendResultDto;

import java.util.List;

/**
 * <p>
 * 综合推荐链
 * 注意，该推荐链不能是单例
 * </p>
 *
 * @author yangwei
 * @since 2021-08-28 13:50
 */
@Slf4j
public class CompositeRecommenderChain implements IRecommenderChain {
	/**
	 * 默认从0开始
	 */
	private int currentIndex = -1;
	/**
	 * 推荐器
	 */
	private List<IRecommender> recommenders;
	/**
	 * 推荐器的数量
	 */
	private Integer recommenderSize;
	/**
	 * 推荐类别
	 */
	private String category;


	public CompositeRecommenderChain(List<IRecommender> recommenders,String category){
		this.recommenders = recommenders;
		this.recommenderSize = recommenders.size();
		this.category = category;
	}

	@Override
	public void doRecommend(String userId, int recommendNum, List<RecommendResultDto> result) {
		// 已经推荐完成足够的数量
		if (recommendNum <= 0) {
			return;
		}
		/**
		 * 推荐器未获取到，一般是所有的推荐器已处理
		 * 但能够走到这说明所有的推荐器已处理，但需要的推荐数量还不够
		 */
		IRecommender recommender = getRecommender();
		if (recommender == null) {
			recommendFallback(userId,recommendNum,result);
			return;
		}
		// 推荐剩余数据量的
		List<RecommendResultDto> recommend = recommender.recommend(userId, recommendNum,category);
		int currentRecommendNum = 0;
		if(CollectionUtils.isNotEmpty(recommend)){
			currentRecommendNum = recommend.size();
			result.addAll(recommend);
		}
		// 调用下一个推荐器，进行推荐剩余的数量
		doRecommend(userId,recommendNum - currentRecommendNum,result);
	}

	/**
	 * 获取推荐器
	 * @return
	 */
	private IRecommender getRecommender(){
		if (++currentIndex > recommenderSize - 1) {
			// 已经执行完了
			return null;
		}
		return recommenders.get(currentIndex);

	}

	/**
	 * 推荐备用处理，所有的推荐器已处理完成，但推荐数量仍还不够
	 * 可以在这里进行补充剩余的数据
	 * @param userId
	 * @param recommendNum
	 * @param result
	 */
	protected void recommendFallback(String userId, int recommendNum, List<RecommendResultDto> result){
		log.warn("所有的推荐器已处理完成，但推荐数量仍还不够，userId={}",userId);
		MonitorTool.count("compositeRecommenderChain.fallback","所有的推荐器已处理完成，但推荐数量仍还不够");
	}
}
